﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WordNet.Core.Morphy
{
    public class StemmingRule: IStemmingRule
    {
        private readonly POS pos;
        private readonly String suffix;
        private readonly String ending;
        private readonly HashSet<String> ignoreSet;

        public StemmingRule(String suffix, String ending, POS pos, params String[] ignore)
        {
            // should not be null, empty, or all whitespace
            if (String.IsNullOrWhiteSpace(suffix))
                throw new ArgumentNullException();
            // should not be null
            if (ending == null)
                throw new ArgumentNullException();
            // might not be null
            if (pos == null)
                throw new ArgumentNullException();

            // allocate avoid set
            HashSet<String> ignoreSet = new HashSet<string>();

            // ignore can be null or empty
            if (ignore != null && ignore.Length > 0)
            {
                foreach (String avoidStr in ignore)
                {
                    // but not contain nulls or empties
                    if (String.IsNullOrWhiteSpace(avoidStr))
                        throw new ArgumentException();
                    ignoreSet.Add(avoidStr);
                }
            }

            if (ignoreSet.Contains(suffix))
                throw new ArgumentException();

            this.pos = pos;
            this.suffix = suffix;
            this.ending = ending;
            this.ignoreSet = ignoreSet;

        }

        // the suffix that should be stripped from a word
        public string GetSuffix()
        {
            return suffix;
        }

        // the ending that should be added to a word
        public string GetEnding()
        {
            return ending;
        }

        // the set of suffixes that, when present, indicate this rule
        // should not be applied
        public IEnumerable<String> GetSuffixIgnoreSet()
        {
            return ignoreSet;
        }

        public string ApplyTo(string word)
        {
            return AddSuffixToEnd(word, null);
        }

        public string AddSuffixToEnd(string word, string suffix)
        {
            if (!word.EndsWith(GetSuffix()))
                return null;

            foreach (var suffixToIgnor in GetSuffixIgnoreSet())
            {
                if (word.EndsWith(suffixToIgnor))
                    return null;
            }

            StringBuilder sb = new StringBuilder();
            int len = word.Length - GetSuffix().Length;
            sb.Append(word, 0, len);
            sb.Append(ending);

            if (!String.IsNullOrWhiteSpace(suffix))
                sb.Append(suffix.Trim());

            return sb.ToString();
        }

        public POS PartOfSpeech
        {
            get { return pos; }
        }

    }
}
